﻿'Imports <xmlns="http://tempuri.org/XMLSchemaRequest.xsd">
Imports System.Net
Imports System.Xml
Imports System.Linq
Imports System.Security.Cryptography
Imports System.Text


Public Class BaseRequest
	Dim params As New SortedDictionary(Of String, String)

	Public Function sendPOSTResponse(Optional AuthRequired As Boolean = False) As XDocument
		Dim document As XDocument = GeneratePOSTRequest(AuthRequired)

		System.Net.ServicePointManager.Expect100Continue = False
		Dim http As HttpWebRequest = WebRequest.Create("http://ws.audioscrobbler.com/2.0/")

		http.ServicePoint.Expect100Continue = False
		http.Timeout = 20 * 1000
		http.ProtocolVersion = New Version(1, 0)
		http.Method = "POST"
		http.Headers.Add(Net.HttpRequestHeader.AcceptLanguage, "en")
		http.Proxy() = Nothing


		Dim byteArray As Byte() = System.Text.Encoding.UTF8.GetBytes(document.ToString)
		http.ContentLength = byteArray.Length
		'http.ContentType = "text/xml"

		Dim dataStream As IO.Stream = http.GetRequestStream()
		dataStream.Write(byteArray, 0, byteArray.Length)
		dataStream.Close()

		Dim response As HttpWebResponse = Nothing
		Try
			response = http.GetResponse()
		Catch ex As Exception
			Return Nothing
		End Try

		Dim doc As New XDocument()
		Try
			Dim s As New IO.StreamReader(response.GetResponseStream, System.Text.Encoding.UTF8)
			Dim res() As Byte = System.Text.Encoding.UTF8.GetBytes(s.ReadToEnd)
			Dim str = System.Text.Encoding.UTF8.GetString(res)
			doc = XDocument.Parse(str)
			'doc = XDocument.Load(response.GetResponseStream)
		Catch ex As Exception
			Return Nothing
		End Try

		Return ExtractResponse(doc)
	End Function

	Public Function sendGETResponse(Optional AuthRequired As Boolean = False) As XDocument
		Dim parameters As String = GenerateGETReponse(AuthRequired)
		Dim http As HttpWebRequest = WebRequest.Create("http://ws.audioscrobbler.com/2.0/?" + parameters)
		http.ServicePoint.Expect100Continue = False
		http.Timeout = 20 * 1000
		http.ProtocolVersion = New Version(1, 0)
		http.Method = "GET"
		http.Headers.Add(Net.HttpRequestHeader.AcceptLanguage, "en")


		Dim response As HttpWebResponse = Nothing
		Try
			response = http.GetResponse()
		Catch ex As Exception
		End Try

		Dim doc As New XDocument()
		Try
			Dim s As New IO.StreamReader(response.GetResponseStream, System.Text.Encoding.UTF8)
			Dim res() As Byte = System.Text.Encoding.UTF8.GetBytes(s.ReadToEnd)
			Dim str = System.Text.Encoding.UTF8.GetString(res)
			doc = XDocument.Parse(str)
			'doc = XDocument.Load(response.GetResponseStream)
		Catch ex As Exception

		End Try

		Return doc
	End Function

	Public Function sendGETAuthenticationResponse(Optional AuthRequired As Boolean = False) As XDocument
		Shell("http://ws.audioscrobbler.com/2.0/?api_key=" + My.Settings.api_key + "&token=" + My.Settings.token, AppWinStyle.NormalFocus, True)
		Return Nothing
	End Function

	Public Function GeneratePOSTRequest(Optional AuthRequired As Boolean = False) As XDocument

		If AuthRequired Then
			If Not params.ContainsKey("api_sig") Then
				AddMemberSignature()
			End If
		End If

		Dim methodname As String = ""
		Try
			methodname = params.Item("method")
		Catch ex As Exception

		End Try


		Dim document As XDocument =
		<?xml version="1.0" encoding="utf-8"?>
		<methodCall>
			<methodName><%= methodname %></methodName>
			<params>
				<param>
					<value>
						<struct>
						</struct>
					</value>
				</param>
			</params>
		</methodCall>

		For Each param In params
			If param.Key <> "method" Then
				Dim elem As XElement = document.<methodCall>.<params>.<param>.<value>.<struct>.Last()
				elem.Add(<member><name><%= param.Key %></name><value><string><%= param.Value %></string></value></member>)
			End If
		Next

		Return document
	End Function

	Public Function GenerateGETReponse(Optional AuthRequired As Boolean = False) As String
		Dim str As String = ""

		If AuthRequired Then
			If Not params.ContainsKey("api_sig") Then
				AddMemberSignature()
			End If
		End If

		For Each kv As KeyValuePair(Of String, String) In params
			If kv.Key = "method" Then
				str = EscapeUriData(kv.Key) & "=" & EscapeUriData(kv.Value) & "&" & str
			Else
				str = str & EscapeUriData(kv.Key) & "=" & EscapeUriData(kv.Value) & "&"
			End If
		Next
		'Strip of the last &
		If str.EndsWith("&") Then str = str.Substring(0, str.Length - 1)

		Return str
	End Function


	Public Sub ClearMembers()
		params.Clear()
	End Sub

	Public Sub InitializeMembers(ByVal method As String)
		params.Clear()
		params.Add("method", method)
	End Sub

	Public Sub InitializeMembers(ByVal package As String, ByVal method As String)
		params.Clear()
		params.Add("method", package + "." + method)
	End Sub

	Public Sub AddMember(ByVal name As String, ByVal value As String, Optional ByVal required As Boolean = False)
		If required = False Then
			If Not String.IsNullOrEmpty(value) Then
				params.Add(name, value)
			End If
		Else
			params.Add(name, value)
		End If
	End Sub

	Public Sub AddMemberSignature()
		Dim str As String = ""
		For Each n As Collections.Generic.KeyValuePair(Of String, String) In params
			str = str & ConvertToUTF8(n.Key) & ConvertToUTF8(n.Value)
		Next
		AddMember("api_sig", MD5Hash(str))
	End Sub
	
	Public Function ExtractResponse(ByRef doc As XDocument) As XDocument
		Try
			Dim str As String = doc.<methodResponse>.<params>.<param>.<value>.<string>.Value
			str = Strings.Replace(str, "\""", """")
			str = Strings.Replace(str, "\'", "'")
			doc = XDocument.Parse(str)
		Catch ex As Exception

		End Try
		Return doc
	End Function

	

	Public Function MD5Hash(ByRef str As String) As String
		Dim md5 As MD5 = md5.Create()

		Dim data As Byte() = md5.ComputeHash(Encoding.UTF8.GetBytes(str + My.Settings.secret))
		Dim sBuilder As New StringBuilder()

		' Loop through each byte of the hashed data 
		' and format each one as a hexadecimal string.
		Dim i As Integer
		For i = 0 To data.Length - 1
			sBuilder.Append(data(i).ToString("x2"))
		Next i


		md5.Dispose()
		' Return the hexadecimal string.
		Return sBuilder.ToString()

	End Function

	Public Function ConvertToUTF8(ByVal str As String) As String
		Return ConvertStringEncoding(str, System.Text.Encoding.ASCII, System.Text.Encoding.UTF8)
	End Function

	Public Function ConvertStringEncoding(ByVal s As String, ByVal ConvertFrom As System.Text.Encoding, ByVal ConvertTo As System.Text.Encoding)
		If String.IsNullOrEmpty(s) Then Return ""
		Dim FromBytes() As Byte = ConvertFrom.GetBytes(s)
		Dim ToBytes() As Byte = Encoding.Convert(ConvertFrom, ConvertTo, FromBytes)
		Return New String(ConvertTo.GetChars(ToBytes))
	End Function


	Public Function EscapeUriData(ByVal data As String) As String
		Dim result As String
		If String.IsNullOrEmpty(data) Then Return Nothing
		'Double encode because of last.fm's "&"-bug
		'result = Uri.EscapeDataString(Uri.EscapeDataString(data))
		result = Uri.EscapeDataString(data)
		'Debug.Print("Escaped " & data & " to " & result)
		Return result
	End Function

End Class
